﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using Stauffware.Common.Core;

namespace Stauffware.Common.Console
{
	//#################################################################################
	/// <summary>
	/// Containss all the built-in command-line parameters.
	/// </summary>

	public class BuiltInParamGroup : CmdLineParamGroup
	{
		/// <summary> constructor </summary>
		public BuiltInParamGroup (CmdLineParser clp)
			: base(clp, "-CLP")
		{
			new BuiltInParam(this, "assemblies", this.Assemblies_handler,
				"Displays a list of all the assemblies referenced by this program.");
		}

		//-----------------------------------------------------------------------------

		private int Assemblies_handler (string actualName, ArgValueList argValues)
		{
			SortedSet<AssemblyName> names = new SortedSet<AssemblyName>(new AsmNameComparer());
			this.CollectAssemblies(Assembly.GetEntryAssembly(), names);

			System.Console.WriteLine("Assemblies:");
			foreach (AssemblyName asm in names)
			{
				System.Console.WriteLine("\t" + asm.FullName);
			}

			return 0;
		}

		private void CollectAssemblies (Assembly referencing, SortedSet<AssemblyName> names)
		{
			names.Add(referencing.GetName());

			foreach (AssemblyName asm in referencing.GetReferencedAssemblies())
				if (!names.Contains(asm))
					names.Add(asm);

			foreach (Module mod in referencing.GetModules())
			{
				AssemblyName asm = mod.Assembly.GetName();
				if (asm != null && !names.Contains(asm))
					names.Add(asm);
			}
		}

		private class AsmNameComparer : IComparer<AssemblyName>
		{
			public int Compare (AssemblyName x, AssemblyName y)
			{
				return string.Compare(x.FullName, y.FullName, true);
			}
		}

		//-----------------------------------------------------------------------------
	}

	//#################################################################################
	/// <summary>
	/// A built-in command-line parameter.
	/// </summary>

	internal class BuiltInParam : CmdLineParam
	{
		public override bool HasValue { get { return false; } }

		private readonly Func<string, ArgValueList, int> ArgsHandler;

		//-----------------------------------------------------------------------------
		/// <summary> constructor </summary>

		public BuiltInParam (CmdLineParamGroup group, string name, Type valueType,
					Arity arity, Func<string, ArgValueList, int> handler, string help)
			: base("versions", group, valueType)
		{
			Require.NotNull(handler);
			this.ArgsHandler = handler;
			this.Arity = arity;
			this.Position = 0;		// built-in commands are never positional
			this.IsRequired = false;
			this.Help = help;
			group.Add(this);
		}

		//-----------------------------------------------------------------------------
		/// <summary> constructor </summary>

		public BuiltInParam (CmdLineParamGroup group, string name, 
							 Func<string, ArgValueList, int> handler, string help)
			: this(group, name, null, Arity.None, handler, help)
		{
		}

		//-----------------------------------------------------------------------------

		internal override int ProcessArgs (string actualName, ArgValueList argValues)
		{
			return this.ArgsHandler(actualName, argValues);
		}

		//-----------------------------------------------------------------------------

		internal override string GetValueString ()
		{
			Assert.NotReached();	// why are we calling this on a built-in parameter?!?
			return null;	// shut compiler up
		}

		internal override void SetValue (object value)
		{
			Assert.NotReached();	// why are we calling this on a built-in parameter?!?
		}

		//-----------------------------------------------------------------------------
		/// <summary> Don't log built-in params. </summary>

		public override void Log (TextWriter tw, string linePrefix=null)
		{
		}

		//-----------------------------------------------------------------------------
	}

	//#################################################################################
}
